package com.niiwoo.civet.account.service.local;

import com.alibaba.fastjson.JSON;
import com.niiwoo.activity.event.constant.BizEventRabbitConstant;
import com.niiwoo.activity.event.dto.request.AccountAmountChangeReqDTO;
import com.niiwoo.activity.event.enums.InOrOutTypeEventEnum;
import com.niiwoo.activity.event.enums.UserRoleTypeEventEnum;
import com.niiwoo.civet.account.dao.entity.AccountBase;
import com.niiwoo.civet.account.dao.mapper.AccountBaseMapperExt;
import com.niiwoo.civet.account.dto.response.AccountAmountDTO;
import com.niiwoo.civet.base.constant.OrgConstant;
import com.niiwoo.tripod.consumer.helper.Exceptions;
import com.niiwoo.tripod.lanmao.enums.UserRoleEnum;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.AmqpException;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

/**
 * Created by bincun on 2017/11/7.
 * 处理账户余额service
 */
@Service
@Slf4j
public class AccountBalanceLocalService {

    @Autowired
    private AccountService accountService;
    @Autowired
    private AccountBaseMapperExt accountBaseMapperExt;
    @Autowired
    private RabbitTemplate rabbitTemplate;



    /**
     * 扣减账户余额
     * @param accountId
     * @param amount
     * @return
     */
    @Transactional
    public BigDecimal decreAccountAmount(Long accountId, BigDecimal amount) {
        if (accountId == null || amount == null || amount.compareTo(BigDecimal.ZERO) < 0) {
            Exceptions.throwBizException("ACC10002");
        }

        AccountBase accountBase = accountBaseMapperExt.selectByPrimaryKeyForUpdate(accountId);
        BigDecimal oldBalanceAmount = accountBase.getAvailableAmount();

        BigDecimal newBalanceAmount;
        if (amount.compareTo(BigDecimal.ZERO) == 0) {
            newBalanceAmount = oldBalanceAmount;
        } else {
            newBalanceAmount = oldBalanceAmount.subtract(amount);

            AccountBase record = new AccountBase();
            record.setId(accountId);
            record.setAvailableAmount(newBalanceAmount);
            accountBaseMapperExt.updateByPrimaryKeySelective(record);
        }

        if (newBalanceAmount.compareTo(BigDecimal.ZERO) < 0) {
            Exceptions.throwBizException("ACC10007");
        }

        log.info("账户{}操作前余额{},本次扣减{}, 操作后余额{}", accountId, oldBalanceAmount, amount, newBalanceAmount);

        availableAmountExchangeEvent(accountBase,newBalanceAmount,InOrOutTypeEventEnum.OUT);

        return newBalanceAmount;
    }

    /**
     * 增加账户余额
     * @param accountId
     * @param amount
     * @return
     */
    @Transactional
    public BigDecimal increAccountAmount(Long accountId, BigDecimal amount) {
        if (accountId == null || amount == null || amount.compareTo(BigDecimal.ZERO) < 0) {
            Exceptions.throwBizException("ACC10002");
        }

        AccountBase accountBase = accountBaseMapperExt.selectByPrimaryKeyForUpdate(accountId);
        BigDecimal oldBalanceAmount = accountBase.getAvailableAmount();

        BigDecimal newBalanceAmount;
        if (amount.compareTo(BigDecimal.ZERO) == 0) {
            newBalanceAmount = oldBalanceAmount;
        } else {
            newBalanceAmount = oldBalanceAmount.add(amount);

            AccountBase record = new AccountBase();
            record.setId(accountId);
            record.setAvailableAmount(newBalanceAmount);
            accountBaseMapperExt.updateByPrimaryKeySelective(record);
        }
        log.info("账户{}操作前余额{},本次新增{}, 操作后余额{}", accountId, oldBalanceAmount, amount, newBalanceAmount);

        availableAmountExchangeEvent(accountBase,newBalanceAmount,InOrOutTypeEventEnum.IN);

        return newBalanceAmount;
    }


    /**
     * 根据用户ID和机构ID查询账户信息及余额
     * 有排序，用于web接口
     *
     * @param userId
     * @param orgId
     * @return
     */
    public List<AccountAmountDTO> queryAccountAmountWithOrgId(String userId,String orgId) {
        List<AccountBase> accountBases = new ArrayList<>();
        if(OrgConstant.NIIWOO_ORG_ID.equals(orgId)){
            accountBases = accountService.listNiiwooAccountByUserId(userId);
        }else{
            AccountBase accountBase = accountService.loadOrgAccount(userId,orgId);
            accountBases.add(accountBase);
        }
        List<AccountAmountDTO> list = new ArrayList<>();
        if (!accountBases.isEmpty()) {
            accountBases.forEach(p -> {
                AccountAmountDTO accountAmountDTO = new AccountAmountDTO();
                if (UserRoleEnum.INVESTOR.getValue().equals(p.getAccountRole())) {
                    accountAmountDTO.setAccountRole(UserRoleEnum.INVESTOR.getValue());
                } else if (UserRoleEnum.BORROWERS.getValue().equals(p.getAccountRole())) {
                    accountAmountDTO.setAccountRole(UserRoleEnum.BORROWERS.getValue());
                } else if (UserRoleEnum.GUARANTEECORP.getValue().equals(p.getAccountRole())) {
                    accountAmountDTO.setAccountRole(UserRoleEnum.GUARANTEECORP.getValue());
                }
                accountAmountDTO.setAccountId(p.getId());
                accountAmountDTO.setAccountNo(p.getAccountNo());
                accountAmountDTO.setAvailableAmount(p.getAvailableAmount());
                accountAmountDTO.setActiveAccount(p.getImportUserActiva());
                list.add(accountAmountDTO);
            });
        }
        return list;
    }


    /**
     * 获取投资总金额
     * @param userIds
     * @return
     */
    public BigDecimal getTotalInvestAmount(List<String> userIds) {
        List<String> ids = new ArrayList<>(100);
        int length = userIds.size();
        BigDecimal total = BigDecimal.ZERO;
        int index = 1;
        for (String id : userIds) {
            ids.add(id);
            if (index % 100 == 0 || index == length) {
                BigDecimal availableAmounts = accountBaseMapperExt.countAvailableAmountByUserIdsAndAccountRole(ids, UserRoleEnum.INVESTOR.getValue());
                if (availableAmounts != null) {
                    total = total.add(availableAmounts);
                }
                ids.clear();
            }
            index++;
        }
        return total;
    }

    //余额变更事情
    private void availableAmountExchangeEvent(AccountBase accountBase,BigDecimal newBalanceAmount,InOrOutTypeEventEnum inOrOutTypeEventEnum) {
        AccountAmountChangeReqDTO amountExchangeDTO = new AccountAmountChangeReqDTO();
        amountExchangeDTO.setUserId(accountBase.getUserId());
        amountExchangeDTO.setUpdateDate(new Date());
        amountExchangeDTO.setAmount(newBalanceAmount);
        amountExchangeDTO.setInOrOutTypeEventEnum(inOrOutTypeEventEnum);
        amountExchangeDTO.setUserRoleTypeEventEnum(UserRoleTypeEventEnum.valueOf(accountBase.getAccountRole()));

        try {
            rabbitTemplate.convertAndSend(BizEventRabbitConstant.Exchange.BIZ_EVENT_DIRECT_EXCHANGE, BizEventRabbitConstant.Key.BIZ_EVENT_ACCOUNT_AMOUNT_CHANGE_KEY, amountExchangeDTO);
        } catch (AmqpException e) {
            log.error("余额变更事件同步amountExchangeDTO:{}", JSON.toJSONString(amountExchangeDTO), e);
        }

    }


}
